با Tox به تست چند محیطی مسلط شوید. این راهنما شامل راهاندازی tox.ini، ادغام CI/CD و استراتژیهای پیشرفته برای کد پایتون بینقص در نسخهها، وابستگیها و سیستمعاملهای مختلف است.
اتوماسیون تست Tox: یک بررسی عمیق در تست چند محیطی برای تیمهای جهانی
در چشمانداز نرمافزاری جهانی امروز، عبارت "روی سیستم من کار میکند" چیزی بیش از یک کلیشه توسعهدهنده است؛ این یک ریسک تجاری قابل توجه است. کاربران، مشتریان و همکاران شما در سراسر جهان پراکنده هستند و از مجموعهای متنوع از سیستمعاملها، نسخههای پایتون و پشتههای وابستگی استفاده میکنند. چگونه میتوانید اطمینان حاصل کنید که کد شما نه تنها کارآمد، بلکه به طور قابل اعتماد برای همه، در هر کجا، قوی و پایدار است؟
پاسخ در تست سیستماتیک، خودکار و چند محیطی نهفته است. اینجاست که Tox، یک ابزار اتوماسیون مبتنی بر خط فرمان، به بخشی ضروری از جعبه ابزار توسعهدهنده مدرن پایتون تبدیل میشود. این ابزار، تست را استاندارد میکند و به شما امکان میدهد تا تستها را در یک ماتریس از پیکربندیها با یک دستور واحد تعریف و اجرا کنید.
این راهنمای جامع، شما را از اصول اولیه Tox تا استراتژیهای پیشرفته برای تست چند محیطی همراهی خواهد کرد. ما بررسی خواهیم کرد که چگونه یک خط لوله تست انعطافپذیر بسازیم که اطمینان حاصل کند نرمافزار شما سازگار، پایدار و آماده برای مخاطبان جهانی است.
تست چند محیطی چیست و چرا حیاتی است؟
تست چند محیطی، اجرای مجموعه تست شما در برابر پیکربندیهای متعدد و متمایز است. این پیکربندیها، یا "محیطها"، معمولاً بر اساس موارد زیر متفاوت هستند:
- نسخههای مفسر پایتون: آیا کد شما روی پایتون 3.8 به همان خوبی که روی پایتون 3.11 کار میکند، عمل میکند؟ در مورد پایتون 3.12 آینده چطور؟
- نسخههای وابستگی: برنامه شما ممکن است به کتابخانههایی مانند Django، Pandas یا Requests متکی باشد. آیا در صورتی که کاربر نسخه کمی قدیمیتر یا جدیدتر از این بستهها را داشته باشد، خراب میشود؟
- سیستمعاملها: آیا کد شما مسیرهای فایل و فراخوانیهای سیستمی را به درستی در ویندوز، macOS و لینوکس مدیریت میکند؟
- معماریها: با ظهور پردازندههای مبتنی بر ARM (مانند Apple Silicon)، تست بر روی معماریهای مختلف CPU (x86_64, arm64) به طور فزایندهای اهمیت پیدا میکند.
توجیه تجاری برای یک استراتژی چند محیطی
سرمایهگذاری زمان برای راهاندازی این نوع تست، فقط یک تمرین آکادمیک نیست؛ بلکه پیامدهای تجاری مستقیمی دارد:
- کاهش هزینههای پشتیبانی: با شناسایی زودهنگام مشکلات سازگاری، از سیل درخواستهای پشتیبانی از سوی کاربرانی که محیطهای آنها را پیشبینی نکرده بودید، جلوگیری میکنید.
- افزایش اعتماد کاربر: نرمافزاری که به طور قابل اعتماد در تنظیمات مختلف کار میکند، با کیفیتتر تلقی میشود. این برای کتابخانههای منبع باز و محصولات تجاری به یک اندازه حیاتی است.
- امکان ارتقاء روانتر: هنگامی که یک نسخه جدید پایتون منتشر میشود، میتوانید به سادگی آن را به ماتریس تست خود اضافه کنید. اگر تستها با موفقیت انجام شوند، میدانید که آماده پشتیبانی از آن هستید. اگر شکست بخورند، لیستی روشن و قابل اقدام از آنچه نیاز به اصلاح دارد، در اختیار دارید.
- پشتیبانی از تیمهای جهانی: این اطمینان را میدهد که یک توسعهدهنده در یک کشور با استفاده از جدیدترین ابزارها میتواند به طور موثر با تیمی در منطقه دیگری که ممکن است بر روی یک پشته سازمانی استاندارد و کمی قدیمیتر باشد، همکاری کند.
معرفی Tox: مرکز فرماندهی اتوماسیون شما
Tox برای حل این مشکل به شیوهای زیبا طراحی شده است. در هسته خود، Tox ایجاد محیطهای مجازی پایتون ایزوله را خودکار میکند، پروژه شما و وابستگیهای آن را در آنها نصب میکند، و سپس دستورات تعریف شده شما (مانند تستها، لینترها، یا ساخت مستندات) را اجرا میکند.
همه اینها توسط یک فایل پیکربندی واحد و ساده کنترل میشود: tox.ini
.
شروع کار: نصب و پیکربندی اولیه
نصب با pip ساده است:
pip install tox
سپس، یک فایل tox.ini
در ریشه پروژه خود ایجاد کنید. بیایید با یک پیکربندی حداقلی برای تست در برابر چندین نسخه پایتون شروع کنیم.
مثال: یک tox.ini
اولیه
[tox] min_version = 3.7 isolated_build = true envlist = py38, py39, py310, py311 [testenv] description = Run the main test suite deps = pytest commands = pytest
بیایید این را تجزیه و تحلیل کنیم:
- بخش
[tox]
: این برای تنظیمات عمومی Tox است. min_version
: حداقل نسخه Tox مورد نیاز برای اجرای این پیکربندی را مشخص میکند.isolated_build
: یک بهترین روش مدرن (PEP 517) که تضمین میکند بسته شما قبل از نصب برای تست، در یک محیط ایزوله ساخته شود.envlist
: این قلب تست چند محیطی است. لیستی از محیطهایی که میخواهید Tox آنها را مدیریت کند، با کاما از هم جدا شدهاند. در اینجا، ما چهار محیط تعریف کردهایم: یکی برای هر نسخه پایتون از 3.8 تا 3.11.- بخش
[testenv]
: این یک الگو برای تمام محیطهای تعریف شده درenvlist
است. description
: یک پیام مفید که توضیح میدهد محیط چه کاری انجام میدهد.deps
: لیستی از وابستگیهای مورد نیاز برای اجرای دستورات شما. در اینجا، ما فقط بهpytest
نیاز داریم.commands
: دستوراتی که باید در محیط مجازی اجرا شوند. در اینجا، ما به سادگی تسترانرpytest
را اجرا میکنیم.
برای اجرای این، به دایرکتوری ریشه پروژه خود در ترمینال بروید و به سادگی تایپ کنید:
tox
اکنون Tox مراحل زیر را برای هر محیط در `envlist` (py38, py39 و غیره) انجام خواهد داد:
- مفسر پایتون مربوطه را در سیستم شما جستجو میکند (به عنوان مثال، `python3.8`, `python3.9`).
- یک محیط مجازی جدید و ایزوله در داخل دایرکتوری
.tox/
ایجاد میکند. - پروژه شما و وابستگیهای ذکر شده در `deps` را نصب میکند.
- دستورات ذکر شده در `commands` را اجرا میکند.
اگر هر مرحلهای در هر محیطی با شکست مواجه شود، Tox خطا را گزارش کرده و با یک کد وضعیت غیرصفر خارج میشود، که آن را برای سیستمهای یکپارچهسازی مداوم (CI) عالی میکند.
بررسی عمیق: ساخت یک tox.ini
قدرتمند
تنظیمات اولیه قدرتمند است، اما جادوی واقعی Tox در گزینههای پیکربندی انعطافپذیر آن برای ایجاد ماتریسهای تست پیچیده نهفته است.
محیطهای مولد: کلید تست ترکیبی
تصور کنید کتابخانهای دارید که باید از نسخههای 3.2 و 4.2 جنگو پشتیبانی کند که روی پایتون 3.9 و 3.10 اجرا میشوند. تعریف دستی هر چهار ترکیب تکراری خواهد بود:
روش تکراری: envlist = py39-django32, py39-django42, py310-django32, py310-django42
Tox یک نحو مولد بسیار تمیزتر با استفاده از کروشههای فرفری {}
ارائه میدهد:
روش مولد: envlist = {py39,py310}-django{32,42}
این یک خط به همان چهار محیط گسترش مییابد. این رویکرد بسیار مقیاسپذیر است. اضافه کردن یک نسخه جدید پایتون یا نسخه جنگو تنها با اضافه کردن یک آیتم به لیست مربوطه امکانپذیر است.
تنظیمات شرطی فاکتور: سفارشیسازی هر محیط
[tox] envlist = {py39,py310}-django{32,42} [testenv] deps = pytest django32: Django>=3.2,<3.3 django42: Django>=4.2,<4.3 commands = pytest
در اینجا، خط `django32: Django>=3.2,<3.3` به Tox میگوید: "فقط این وابستگی را شامل شود اگر نام محیط شامل فاکتور `django32` باشد." به طور مشابه برای `django42`. Tox به اندازه کافی هوشمند است که نامهای محیط (مانند `py310-django42`) را تجزیه و تحلیل کرده و تنظیمات صحیح را اعمال کند.
این یک ویژگی فوقالعاده قدرتمند برای مدیریت موارد زیر است:
- وابستگیهایی که با نسخههای قدیمیتر/جدیدتر پایتون سازگار نیستند.
- تست در برابر نسخههای مختلف یک کتابخانه اصلی (Pandas, NumPy, SQLAlchemy و غیره).
- نصب مشروط وابستگیهای خاص پلتفرم.
ساختاردهی پروژه شما فراتر از تستهای اولیه
یک خط لوله کیفیت قوی شامل چیزی بیش از اجرای تستها است. شما همچنین نیاز دارید تا لینترها، بررسیکنندههای نوع (type checkers) را اجرا کرده و مستندات را بسازید. این یک بهترین روش است که محیطهای Tox جداگانه برای این وظایف تعریف کنید.
[tox] envlist = py{39,310}, lint, typing, docs [testenv] deps = pytest commands = pytest [testenv:lint] description = Run linters (ruff, black) basepython = python3.10 deps = ruff black commands = ruff check . black --check . [testenv:typing] description = Run static type checker (mypy) basepython = python3.10 deps = mypy # also include other dependencies with type hints django djangorestframework commands = mypy my_project/ [testenv:docs] description = Build the documentation basepython = python3.10 deps = sphinx commands = sphinx-build -b html docs/source docs/build/html
در اینجا چه چیزهای جدیدی داریم:
- بخشهای محیطی خاص: ما `[testenv:lint]`, `[testenv:typing]`, و `[testenv:docs]` را اضافه کردهایم. این بخشها تنظیماتی را به طور خاص برای آن محیطهای نامگذاری شده تعریف میکنند و تنظیمات پیشفرض در `[testenv]` را نادیده میگیرند.
basepython
: برای محیطهای غیر تستی مانند `lint` یا `docs`، اغلب نیازی به اجرای آنها روی هر نسخه پایتون نداریم. `basepython` به ما امکان میدهد آنها را به یک مفسر خاص سنجاق کنیم، که باعث میشود سریعتر و قطعیتر باشند.- جداسازی تمیز: این ساختار وابستگیهای شما را تمیز نگه میدارد. محیط `lint` فقط لینترها را نصب میکند؛ محیطهای تست اصلی شما به آنها نیازی ندارند.
اکنون میتوانید همه محیطها را با `tox`، مجموعهای خاص را با `tox -e py310,lint`، یا فقط یک محیط را با `tox -e docs` اجرا کنید.
ادغام Tox با CI/CD برای اتوماسیون در مقیاس جهانی
اجرای Tox به صورت محلی عالی است، اما قدرت واقعی آن زمانی آشکار میشود که در یک خط لوله یکپارچهسازی مداوم/استقرار مداوم (CI/CD) ادغام شود. این تضمین میکند که هر تغییر کد به طور خودکار در برابر ماتریس تست کامل شما اعتبارسنجی میشود.
سرویسهایی مانند GitHub Actions، GitLab CI و Jenkins برای این کار عالی هستند. آنها میتوانند وظایف شما را روی سیستمعاملهای مختلف اجرا کنند، که به شما امکان میدهد یک ماتریس سازگاری جامع با سیستمعامل بسازید.
مثال: یک Workflow در GitHub Actions
بیایید یک Workflow در GitHub Actions ایجاد کنیم که محیطهای Tox ما را به صورت موازی در لینوکس، macOS و ویندوز اجرا کند.
یک فایل در .github/workflows/ci.yml
ایجاد کنید:
name: CI on: [push, pull_request] jobs: test: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: ['3.8', '3.9', '3.10', '3.11'] steps: - name: Check out repository uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install Tox run: pip install tox tox-gh-actions - name: Run Tox run: tox -e py
بیایید این workflow را تحلیل کنیم:
strategy.matrix
: این هسته ماتریس CI ماست. GitHub Actions یک وظیفه (job) جداگانه برای هر ترکیب از `os` و `python-version` ایجاد خواهد کرد. برای این پیکربندی، این یعنی 3 سیستمعامل × 4 نسخه پایتون = 12 وظیفه موازی.actions/setup-python@v4
: این اکشن استاندارد، نسخه خاص پایتون مورد نیاز برای هر وظیفه را راهاندازی میکند.tox-gh-actions
: این یک پلاگین مفید Tox است که به طور خودکار نسخه پایتون را در محیط CI به محیط صحیح Tox نگاشت میکند. به عنوان مثال، در وظیفهای که روی پایتون 3.9 اجرا میشود، `tox -e py` به طور خودکار به اجرای `tox -e py39` تبدیل میشود. این شما را از نوشتن منطق پیچیده در اسکریپت CI خود نجات میدهد.
اکنون، هر بار که کد push میشود، کل ماتریس تست شما به طور خودکار در هر سه سیستمعامل اصلی اجرا میشود. شما بازخورد فوری در مورد اینکه آیا تغییری ناسازگاری ایجاد کرده است یا خیر دریافت میکنید، که به شما امکان میدهد با اطمینان برای یک پایگاه کاربر جهانی توسعه دهید.
استراتژیهای پیشرفته و بهترین شیوهها
ارسال آرگومان به دستورات با {posargs}
گاهی اوقات شما نیاز دارید آرگومانهای اضافی را به تسترانر خود ارسال کنید. به عنوان مثال، ممکن است بخواهید یک فایل تست خاص را اجرا کنید: pytest tests/test_api.py
. Tox این را با جایگزینی {posargs}
پشتیبانی میکند.
`tox.ini` خود را اصلاح کنید:
[testenv] deps = pytest commands = pytest {posargs}
اکنون، میتوانید Tox را به این صورت اجرا کنید:
tox -e py310 -- -k \"test_login\" -v
--
آرگومانهای مربوط به Tox را از آرگومانهای مربوط به دستور جدا میکند. هر چیزی بعد از آن جایگزین `{posargs}` خواهد شد. Tox اجرا خواهد کرد: pytest -k \"test_login\" -v
در داخل محیط `py310`.
کنترل متغیرهای محیطی
برنامه شما ممکن است بر اساس متغیرهای محیطی رفتار متفاوتی داشته باشد (مثلاً `DJANGO_SETTINGS_MODULE`). دستور `setenv` به شما امکان میدهد اینها را در محیطهای Tox خود کنترل کنید.
[testenv] setenv = PYTHONPATH = . MYAPP_MODE = testing [testenv:docs] setenv = SPHINX_BUILD = 1
نکاتی برای اجرای سریعتر Tox
با افزایش ماتریس شما، اجرای Tox میتواند کند شود. در اینجا چند نکته برای افزایش سرعت آنها آورده شده است:
- حالت موازی: `tox -p auto` را اجرا کنید تا Tox محیطهای شما را به صورت موازی، با استفاده از تعداد هستههای CPU موجود، اجرا کند. این در ماشینهای مدرن بسیار موثر است.
- بازسازی انتخابی محیطها: به طور پیشفرض، Tox محیطها را دوباره استفاده میکند. اگر وابستگیهای شما در `tox.ini` یا `requirements.txt` تغییر کنند، باید به Tox بگویید که محیط را از ابتدا بازسازی کند. از پرچم بازسازی استفاده کنید: `tox -r -e py310`.
- کش کردن CI: در خط لوله CI/CD خود، دایرکتوری
.tox/
را کش کنید. این میتواند به طور قابل توجهی سرعت اجراهای بعدی را افزایش دهد زیرا وابستگیها هر بار نیاز به دانلود و نصب نخواهند داشت، مگر اینکه تغییر کنند.
موارد استفاده جهانی در عمل
بیایید بررسی کنیم که چگونه این موضوع در انواع مختلف پروژهها در یک زمینه جهانی کاربرد دارد.
سناریوی 1: یک کتابخانه تجزیه و تحلیل داده منبع باز
شما یک کتابخانه محبوب را که بر اساس Pandas و NumPy ساخته شده است، نگهداری میکنید. کاربران شما دانشمندان داده و تحلیلگران در سراسر جهان هستند.
- چالش: شما باید از چندین نسخه پایتون، Pandas، NumPy پشتیبانی کنید و اطمینان حاصل کنید که روی سرورهای لینوکس، لپتاپهای macOS و دسکتاپهای ویندوز کار میکند.
- راه حل Tox:
envlist = {py39,py310,py311}-{pandas1,pandas2}-{numpy18,numpy19}
`tox.ini` شما از تنظیمات شرطی فاکتور برای نصب نسخههای صحیح کتابخانه برای هر محیط استفاده میکند. workflow گیتهاب اکشنز شما این ماتریس را در هر سه سیستمعامل اصلی تست میکند. این تضمین میکند که کاربری در برزیل که از نسخه قدیمیتر Pandas استفاده میکند، همان تجربه قابل اعتماد را به عنوان کاربری در ژاپن با جدیدترین پشته دریافت میکند.
سناریوی 2: یک برنامه SaaS سازمانی با یک کتابخانه مشتری
شرکت شما، مستقر در اروپا، یک محصول SaaS ارائه میدهد. مشتریان شما شرکتهای بزرگ و جهانی هستند که بسیاری از آنها از نسخههای قدیمیتر با پشتیبانی بلندمدت (LTS) از سیستمعاملها و پایتون برای ثبات استفاده میکنند.
- چالش: تیم توسعه شما از ابزارهای مدرن استفاده میکند، اما کتابخانه مشتری شما باید با محیطهای قدیمیتر سازمانی سازگار با عقب (backward-compatible) باشد.
- راه حل Tox:
envlist = py38, py39, py310, py311
`tox.ini` شما اطمینان حاصل میکند که تمام تستها در برابر پایتون 3.8 که ممکن است استاندارد یک مشتری اصلی در آمریکای شمالی باشد، با موفقیت انجام شوند. با اجرای خودکار این در CI، از معرفی تصادفی ویژگیهایی توسط توسعهدهندگان که از نحو یا کتابخانههایی استفاده میکنند که فقط در نسخههای جدیدتر پایتون موجود هستند، جلوگیری میکنید، که از شکستهای پرهزینه استقرار جلوگیری میکند.
نتیجهگیری: انتشار با اطمینان جهانی
تست چند محیطی دیگر یک لوکس نیست؛ بلکه یک عمل اساسی برای توسعه نرمافزار حرفهای و با کیفیت بالا است. با پذیرش اتوماسیون با Tox، این چالش پیچیده را به یک فرآیند ساده و قابل تکرار تبدیل میکنید.
با تعریف محیطهای پشتیبانی شده خود در یک فایل tox.ini
و ادغام آن با یک خط لوله CI/CD، یک دروازه کیفیت قدرتمند ایجاد میکنید. این دروازه تضمین میکند که برنامه شما قوی، سازگار و آماده برای مخاطبان متنوع و جهانی است. میتوانید نگرانی در مورد مشکل وحشتناک "روی سیستم من کار میکند" را متوقف کرده و با اطمینان کد را منتشر کنید که روی سیستم همه کار خواهد کرد، بدون توجه به اینکه در کجای جهان هستند.